/*
 *  This program is derived from Extenex Corporation's SA-1100 usb
 *  controller core driver by MIZI.
 *
 *  usb_ctl.c
 *
 *  S3C2410 USB controller core driver.
 *
 *  This file provides interrupt routing and overall coordination
 *  of the five endpoints.
 *
 *  Seungbum Lim <shawn@mizi.com>
 */

/*
 * ep0 - register
 * ep2~4 - dual port async. RAM (interrupt or DMA)
 *
 * config:
 *  ep0.
 *  ep2 : input - DMA_CH0 ?
 *  ep1 : output - DMA_CH3 ?
 */

#include <arch.h>
#include "util.h"
#include "s3c2410_usb.h"
#include "usb_ctrl.h"


#define USB_CTRL_DBG 1
#if USB_CTRL_DBG
#define DBGOUT(x) x
#else
#define DBGOUT(x)
#endif

//////////////////////////////////////////////////////////////////////////////
// Prototypes
//////////////////////////////////////////////////////////////////////////////
int usbctl_next_state_on_event( int event );
//static void udc_int_hndlr(int, void *);
static void initialize_descriptors( void );
void ChangeUPllValue(int mdiv, int pdiv, int sdiv);
void reset_usbd(void);
void reconfig_usbd(void);
void usb_soft_connect(int enable);
//#define USB_DEBUG 1

#ifdef USB_DEBUG
#define LOG(arg...) printk(__FILE__":"__FUNCTION__"(): " ##arg)
#else
#define LOG(arg...) (void)(0)
#endif

#if CONFIG_PROC_FS
#define PROC_NODE_NAME "usb"
static int usbctl_read_proc(char *page, char **start, off_t off,
                            int count, int *eof, void *data);
#endif

#define kerror -1
//////////////////////////////////////////////////////////////////////////////
// Globals
//////////////////////////////////////////////////////////////////////////////
static const char pszMe[] = "usbctl: ";
struct usb_info_t usbd_info;  /* global to ep0, usb_recv, usb_send */
//static int cnt=0;

int usb_speed = USB_SPEED_FULL;

int usb_connected = 0;

/* device descriptors */
static desc_t desc;

u16 usb_vendor_id = 0x0525;
u16 usb_product_id = 0xa4a7;

#define MAX_STRING_DESC 8
static string_desc_t * string_desc_array[ MAX_STRING_DESC ];
static string_desc_t sd_zero;  /* special sd_zero holds language codes */

// called when configured
static usb_notify_t configured_callback = NULL;

enum {    kStateZombie  = 0,  kStateZombieSuspend  = 1,
        kStateDefault = 2,  kStateDefaultSuspend = 3,
        kStateAddr    = 4,  kStateAddrSuspend    = 5,
        kStateConfig  = 6,  kStateConfigSuspend  = 7
};

static int device_state_machine[8][6] = {
//                suspend               reset          resume     adddr config deconfig
/* zombie */  {  kStateZombieSuspend,  kStateDefault, kError,    kError, kError, kError },
/* zom sus */ {  kError, kStateDefault, kStateZombie, kError, kError, kError },
/* default */ {  kStateDefaultSuspend, kError, kStateDefault, kStateAddr, kError, kError },
/* def sus */ {  kError, kStateDefault, kStateDefault, kError, kError, kError },
/* addr */    {  kStateAddrSuspend, kStateDefault, kError, kError, kStateConfig, kError },
/* addr sus */{  kError, kStateDefault, kStateAddr, kError, kError, kError },
/* config */  {  kStateConfigSuspend, kStateDefault, kError, kError, kError, kStateAddr },
/* cfg sus */ {  kError, kStateDefault, kStateConfig, kError, kError, kError }
};

/* "device state" is the usb device framework state, as opposed to the
   "state machine state" which is whatever the driver needs and is much
   more fine grained
*/
static int sm_state_to_device_state[8] =
//  zombie           zom suspend          default            default sus
{ USB_STATE_POWERED, USB_STATE_SUSPENDED, USB_STATE_DEFAULT, USB_STATE_SUSPENDED,
// addr              addr sus             config                config sus
  USB_STATE_ADDRESS, USB_STATE_SUSPENDED, USB_STATE_CONFIGURED, USB_STATE_SUSPENDED
};

static char * state_names[8] =
{ "zombie", "zombie suspended", "default", "default suspended",
  "address", "address suspended", "configured", "config suspended"
};

static char * event_names[6] =
{ "suspend", "reset", "resume",
  "address assigned", "configure", "de-configure"
};

static char * device_state_names[] =
{ "not attached", "attached", "powered", "default",
  "address", "configured", "suspended" };

static int sm_state = kStateZombie;


//////////////////////////////////////////////////////////////////////////////
// Dump functions
//////////////////////////////////////////////////////////////////////////////
void dump_udcreg(void)
{
    printk("In dump_udcreg\n");
    printk("rFUNC_ADDR_REG      %x\n", rFUNC_ADDR_REG    );
    printk("rPWR_REG            %x\n", rPWR_REG          );
    printk("rEP_INT_REG         %x\n", rEP_INT_REG       );
    printk("rUSB_INT_REG        %x\n", rUSB_INT_REG      );
    printk("rEP_INT_EN_REG      %x\n", rEP_INT_EN_REG    );
    printk("rUSB_INT_EN_REG     %x\n", rUSB_INT_EN_REG   );
    printk("rFRAME_NUM1_REG     %x\n", rFRAME_NUM1_REG   );
    printk("rFRAME_NUM2_REG     %x\n", rFRAME_NUM2_REG   );
    printk("rINDEX_REG          %x\n", rINDEX_REG        );
    printk("rMAXP_REG           %x\n", rMAXP_REG         );
    printk("rEP0_CSR            %x\n", rEP0_CSR          );
    printk("rIN_CSR1_REG        %x\n", rIN_CSR1_REG      );
    printk("rIN_CSR2_REG        %x\n", rIN_CSR2_REG      );
    printk("rOUT_CSR1_REG       %x\n", rOUT_CSR1_REG     );
    printk("rOUT_CSR2_REG       %x\n", rOUT_CSR2_REG     );
    printk("rOUT_FIFO_CNT1_REG  %x\n", rOUT_FIFO_CNT1_REG);
    printk("rOUT_FIFO_CNT2_REG  %x\n", rOUT_FIFO_CNT2_REG);
    printk("rEP0_FIFO           %x\n", rEP0_FIFO         );
    printk("rEP1_FIFO           %x\n", rEP1_FIFO         );
    printk("rEP2_FIFO           %x\n", rEP2_FIFO         );
    printk("rEP3_FIFO           %x\n", rEP3_FIFO         );
    printk("rEP4_FIFO           %x\n", rEP4_FIFO         );
}

//////////////////////////////////////////////////////////////////////////////
// Reset Fucntions
//////////////////////////////////////////////////////////////////////////////

void reset_usbd(void)
{
    int i;

    rPWR_REG = UD_PWR_DEFAULT | UD_PWR_RESET; /* rPWR_REG default value, MCU_RESET */
    rPWR_REG;
    rPWR_REG = UD_PWR_DEFAULT;

    LOG("rPWR_REG = 0x%08x\n", rPWR_REG);

    for(i = 0; i< 0x100; i++) ;
}


void reconfig_usbd(void)
{

    LOG("\n");

//    /* sec like, shawn */
//    ep0_state = EP0_STATE_IDLE;
//    set_configuration = 1;
//    set_interface = 1;
//    device_status = 0;
//    ep0_status = 0;
//    ep_bulk_in_status = 0;
//    ep_bulk_out_status = 0;

//        rPWR_REG = UD_PWR_DEFAULT;
        /* EP0 */
    printk("ep0 init\n");
    rINDEX_REG = UD_INDEX_EP0;
    rMAXP_REG = UD_MAXP_8; // 8 byte

#if 1
//    rINDEX_REG = UD_INDEX_EP0;
//    rIN_CSR1_REG = EP0_CSR_SOPKTRDY | EP0_CSR_SSE;

    /* EP1 IN*/
    printk("ep1 init\n");
    rINDEX_REG = UD_INDEX_EP1;
    rMAXP_REG = UD_MAXP_64; // 64 byte
//    rINDEX_REG = UD_INDEX_EP1;
//    rIN_CSR1_REG = UD_ICSR1_FFLUSH | UD_ICSR1_CLRDT; // fifo flush, data toggle
//    rINDEX_REG = UD_INDEX_EP1;
//    rIN_CSR2_REG = UD_ICSR2_MODEIN | UD_OCSR2_DMAIEN; // input mode; dma interrupt disable
#ifdef USE_USBD_DMA
    rIN_CSR2_REG &= ~UD_ICSR2_DMAIEN;
#endif

        /* EP2 OUT*/
    printk("ep2 init\n");
    rINDEX_REG = UD_INDEX_EP2;
    rMAXP_REG = UD_MAXP_64; // 64 byte
//    rINDEX_REG = UD_INDEX_EP2;
//    rIN_CSR1_REG = UD_ICSR1_FFLUSH | UD_ICSR1_CLRDT; // fifo flush, data toggle
//    rINDEX_REG = UD_INDEX_EP2;
//    rIN_CSR2_REG = UD_ICSR2_DMAIEN; // output mode, IN_PKT_RDY dis
#ifdef USE_USBD_DMA
    rIN_CSR2_REG &= ~UD_ICSR2_DMAIEN;
#endif
//    rINDEX_REG = UD_INDEX_EP2;
//    rOUT_CSR1_REG = UD_OCSR1_FFLUSH | UD_OCSR1_CLRDT; // fifo flush
//    rINDEX_REG = UD_INDEX_EP2;
//    rOUT_CSR2_REG = UD_OCSR2_DMAIEN; // OUT_PKT_RDY interrupt disable
#ifdef USE_USBD_DMA
    rOUT_CSR2_REG &= ~UD_OCSR2_DMAIEN; // OUT_PKT_RDY interrupt disable
#endif


//    /* EP3 INTERRUPT*/
//    rINDEX_REG = UD_INDEX_EP3;
//    rMAXP_REG = UD_MAXP_8; // 8 byte
//    rINDEX_REG = UD_INDEX_EP3;
//    rIN_CSR2_REG = UD_ICSR2_ISO; // INTERRUPT
//    rINDEX_REG = UD_INDEX_EP3;
//    rOUT_CSR2_REG = UD_ICSR2_ISO; // INTERRUPT


//    rEP_INT_EN_REG = UD_INTE_EP0 | UD_INTE_EP2 | UD_INTE_EP1 | UD_INDEX_EP3;
//    rUSB_INT_EN_REG = UD_USBINTE_RESET | UD_USBINTE_SUSPND;
    printk("rPWR_RE init\n");
//    rPWR_REG = 0;
//      bINTCTL(oINTMSK) &= ~(INT_USBD);

#endif
}


//static void
//udc_int_hndlr(int irq, void *dev_id)
//{
//      __u8 saveIdx = rINDEX_REG;
//        __u8 usb_status = rUSB_INT_REG;
//      __u8 usbd_status = rEP_INT_REG;
////    static int sb_debug_cnt = 1;
//
//    LOG("usb_status = 0x%02x, usbd_status = 0x%02x\n",
//            usb_status, usbd_status);
//
//    if ( usb_status & UD_USBINT_RESET ) {
//
//        LOG("\n[%d]RESET interrupt\n",sb_debug_cnt++);
//        if( usbctl_next_state_on_event(kEvReset) != kError ) {
//        LOG("%s Resetting\n",pszMe);
//
//        ep0_reset();
//        ep1_reset();/* output */
//        ep2_reset();/* input */
//
//        }
//
//       // reset_usbd();
//        reconfig_usbd();
//        rUSB_INT_REG = UD_USBINT_RESET; //RESET_INT should be cleared after reconfig_usbd().- by samsung src
//        ep0_state = EP0_STATE_IDLE;
//
//    }
//
//
//    /* RESume Interrupt Request */
//    if ( usb_status & UD_USBINT_RESUM ) {
//         LOG("[%d]RESUME interrupt\n", sb_debug_cnt++);
//        rUSB_INT_REG = UD_USBINT_RESUM;/* clear */
//        usbctl_next_state_on_event( kEvResume );
//
//    }
//
//
//    /* SUSpend Interrupt Request */
//    if ( usb_status & UD_USBINT_SUSPND ) {
//        LOG("[%d]SUSPEND interrupt\n", sb_debug_cnt++);
//        rUSB_INT_REG = UD_USBINT_SUSPND; /* clear */
//        usbctl_next_state_on_event( kEvSuspend );
//
//    }
//
//    if ( usbd_status & UD_INT_EP0 ) {
//        LOG("\n[%d]EP0 interrupt\n",sb_debug_cnt++);
//        rEP_INT_REG = UD_INT_EP0; /* clear */
//        ep0_int_hndlr();
//
//    }
//
//         /* output */
//    if ( usbd_status & UD_INT_EP1 ) {
//        LOG("[%d]EP1 interrupt\n", sb_debug_cnt++);
//        rEP_INT_REG = UD_INT_EP1;/* clear */
//        ep1_int_hndlr(usbd_status);
//
//    }
//        /* input */
//    if ( usbd_status & UD_INT_EP2 ) {
//        LOG("[%d]EP2 interrupt\n", sb_debug_cnt++);
//        rEP_INT_REG = UD_INT_EP2; /* clear */
//        ep2_int_hndlr(usbd_status);
//
//    }
//
//    if(usbd_status & UD_INT_EP3) rEP_INT_REG = UD_INT_EP3;
//    if(usbd_status & UD_INT_EP4) rEP_INT_REG = UD_INT_EP4;
//
////      Clear_pending(INT_USBD);
//    rINDEX_REG= saveIdx;
//
//}



//////////////////////////////////////////////////////////////////////////////
// Public Interface
//////////////////////////////////////////////////////////////////////////////

/* Open S3C2410 usb core on behalf of a client, but don't start running */

int s3c2410_usb_open( const char * client )
{

    LOG("\n");

    if ( usbd_info.client_name != NULL )
      return -1;

    usbd_info.client_name = (char*) client;
    memset(&usbd_info.stats, 0, sizeof(struct usb_stats_t));
    memset(string_desc_array, 0, sizeof(string_desc_array));

    /* hack to start in zombie suspended state */
#if 0
    sm_state = kStateZombieSuspend;
    usbd_info.state = USB_STATE_SUSPENDED;
#endif

    /* create descriptors for enumeration */
    initialize_descriptors();

    printk( "%sOpened for %s\n", pszMe, client );
    dump_udcreg();

    return 0;
}

/* Start running. Must have called usb_open (above) first */
int s3c2410_usb_start( void )
{
//    unsigned long tmp;

    LOG("\n");

     if ( usbd_info.client_name == NULL ) {
          printk( "%s%s - no client registered\n",
                  pszMe, __FUNCTION__ );
          return -1;
     }

    /* MISC. register */
    rMISCCR = rMISCCR & (~((1<<3)|(1<<12)|(1<<13)));

    rCLKSLOW &= ~(1<<7);

//    /* rUPLLCON */    //need to be avoid this operation!!!!!!!!!!!!!!!
//    rUPLLCON = FInsrt(0x78, fPLL_MDIV) | FInsrt(0x02, fPLL_PDIV)
//                | FInsrt(0x03, fPLL_SDIV);
    /* rCLKCON */
    rCLKCON |= CLKCON_USBD;
//  Clear_pending(INT_USBD);

    reconfig_usbd();


//    if (strncmp(to_platform_device(_dev)->name, "s3c2440", 7) == 0) {
//        printk("Detected S3C2440 - increasing FIFO to 128 bytes\n");
//        memory.ep[1].fifo_size = S3C2440_EP_FIFO_SIZE;
//        memory.ep[2].fifo_size = S3C2440_EP_FIFO_SIZE;
//        memory.ep[3].fifo_size = S3C2440_EP_FIFO_SIZE;
//        memory.ep[4].fifo_size = S3C2440_EP_FIFO_SIZE;
//    }

//    spin_lock_init (&udc->lock);
//    udc_info = _dev->platform_data;
//
//    rsrc_start = S3C2410_PA_USBDEV;
//    rsrc_len   = S3C24XX_SZ_USBDEV;
//
//    if (!request_mem_region(rsrc_start, rsrc_len, gadget_name))
//        return -EBUSY;
//
//    base_addr = ioremap(rsrc_start, rsrc_len);
//    if (!base_addr) {
//        retval = -ENOMEM;
//        goto err_mem;
//    }
//
//    device_initialize(&udc->gadget.dev);
//    udc->gadget.dev.parent = _dev;
//    udc->gadget.dev.dma_mask = _dev->dma_mask;
//
//    the_controller = udc;
//    dev_set_drvdata(_dev, udc);


//    udc_disable(udc);
//    udc_reinit(udc);

//    /* irq setup after old hardware state is cleaned up */
//    retval = request_irq(IRQ_USBD, s3c2410_udc_irq,
//        SA_INTERRUPT, gadget_name, udc);
//
//    if (retval != 0) {
//        printk(KERN_ERR "%s: can't get irq %i, err %d\n",
//            gadget_name, IRQ_USBD, retval);
//        retval = -EBUSY;
//        goto err_map;
//    }
//    udc->got_irq = 1;
//    printk(DEBUG_VERBOSE, "%s: got irq %i\n", gadget_name, IRQ_USBD);

//#ifdef ENABLE_SYSFS
//    /* create device files */
//    device_create_file(_dev, &dev_attr_regs);
//#endif
//    return 0;




//     /* start UDC internal machinery running */
//     udelay( 100 );
//
//     /* clear stall - receiver seems to start stalled? */
//    rINDEX_REG = UD_INDEX_EP2; // EP2 input
//    tmp = rIN_CSR1_REG;
//    tmp &= ~(UD_ICSR1_SENTSTL | UD_ICSR1_FFLUSH | UD_ICSR1_UNDRUN);
//        tmp &= ~(UD_ICSR1_PKTRDY | UD_ICSR1_SENDSTL);
//    rIN_CSR1_REG = tmp;
//
//    rINDEX_REG = UD_INDEX_EP1; // EP1 output
//    tmp = rOUT_CSR1_REG;
//    tmp &= ~(UD_OCSR1_SENTSTL | UD_OCSR1_FFLUSH | UD_OCSR1_OVRRUN);
//    tmp &= ~(UD_OCSR1_PKTRDY | UD_OCSR1_SENDSTL);
//    rOUT_CSR1_REG = tmp;
//
//
//    /* flush DMA and fire through some -EAGAINs */
//    ep2_init( usbd_info.dmach_tx );
//    ep1_init( usbd_info.dmach_rx );


    /* clear all top-level sources */
    rEP_INT_REG = UD_INT_EP0 | UD_INT_EP1 | UD_INT_EP2| UD_INT_EP3;
    rUSB_INT_REG = UD_USBINT_RESET | UD_USBINT_RESUM | UD_USBINT_SUSPND;

    //set default power state
    rPWR_REG = 0;

    //enable reset and suspend interrupt
    rUSB_INT_EN_REG = 0x5;

    //enable ep0 interrup
    rEP_INT_EN_REG = 0x1;

    printk( "%sStarted for %s\n", pszMe, usbd_info.client_name );
    dump_udcreg();

    return 0;
}

/* Stop USB core from running */
int s3c2410_usb_stop( void )
{
    //note here: stop the clock to let usb gone, or next enumerate has problem
       /* MISC. register */
    rMISCCR = rMISCCR  |(((1<<3)|(1<<12)|(1<<13)));

    rCLKSLOW |= (1<<7);

    //stop clock
    rCLKCON &= ~CLKCON_USBD;

    usb_soft_connect(0);

    //disable all usb interrupt
    rUSB_INT_EN_REG = 0;
    rEP_INT_EN_REG = 0;

    return 0;
}


/* Tell S3C2410 core client is through using it */
int
s3c2410_usb_close( void )
{
     if ( usbd_info.client_name == NULL ) {
          printk( "%s%s - no client registered\n",
                  pszMe, __FUNCTION__ );
          return -1;
     }
     usbd_info.client_name = NULL;
     return 0;
}

/* set a proc to be called when device is configured */
usb_notify_t s3c2410_set_configured_callback( usb_notify_t func )
{
     usb_notify_t retval = configured_callback;

    LOG("\n");

     configured_callback = func;
     return retval;
}

/*====================================================
 * Descriptor Manipulation.
 * Use these between open() and start() above to setup
 * the descriptors for your device.
 *
 */

/* get pointer to static default descriptor */
desc_t * s3c2410_usb_get_descriptor_ptr( void ) { return &desc; }

/* optional: set a string descriptor */
int pxa_usb_set_string_descriptor( int i, string_desc_t * p )
{
    int retval;
    if ( i < MAX_STRING_DESC ) {
        string_desc_array[i] = p;
        retval = 0;
    }
    else {
        retval = -1;
    }
    return retval;
}

/* optional: get a previously set string descriptor */
string_desc_t * s3c2410_usb_get_string_descriptor( int i )
{
    return ( i < MAX_STRING_DESC )
        ? string_desc_array[i]
        : NULL;
}

config_desc_t * pxa_usb_get_config(int cfgval)
{
    int i;
    desc_t * pdesc = s3c2410_usb_get_descriptor_ptr();
    config_desc_t *cfg = (config_desc_t*) (pdesc->cdb);

    for( i=0; i<pdesc->dev.bNumConfigurations; i++) {
        if( cfg->bConfigurationValue == cfgval ) return cfg;
        cfg = (config_desc_t*) ((unsigned char*)cfg + cfg->wTotalLength);
    }

    return NULL;
}

intf_desc_t * pxa_usb_get_interface( config_desc_t *cfg, int idx)
{
    int i;
    intf_desc_t *intf = (intf_desc_t*) (cfg + 1);

    for( i=0; i < cfg->bNumInterfaces; i++) {
        if( idx == intf->bInterfaceNumber) return intf;
        intf++;
        if( i== 1) {
            intf= (intf_desc_t*)((unsigned long *)intf +sizeof(acm_function));
        }
    }

    return NULL;
}


ep_desc_t * pxa_usb_get_endpoint( intf_desc_t *intf, int idx)
{
    int i;
    ep_desc_t *ep = (ep_desc_t *) (intf+1);


    for( i=0; i< intf->bNumEndpoints; i++) {
        if( idx == (ep->bEndpointAddress & 0xF) ) return ep;
        ep++;
    }
    return NULL;
}


/* optional: kmalloc and unicode up a string descriptor */
string_desc_t *
s3c2410_usb_kmalloc_string_descriptor( const char * p )
{
     string_desc_t * pResult = NULL;

//     LOG("\n");
//
//     if ( p ) {
//          int len = strlen( p );
//          int uni_len = len * sizeof( __u16 );
//          pResult = (string_desc_t*) kmalloc( uni_len + 2, GFP_KERNEL ); /* ugh! */
//          if ( pResult != NULL ) {
//               int i;
//               pResult->bLength = uni_len + 2;
//               pResult->bDescriptorType = USB_DESC_STRING;
//               for( i = 0; i < len ; i++ ) {
//                    pResult->bString[i] = make_word( (__u16) p[i] );
//               }
//          }
//     }
     return pResult;
}

//////////////////////////////////////////////////////////////////////////////
// Exports to rest of driver
//////////////////////////////////////////////////////////////////////////////

/* called by the int handler here and the two endpoint files when interesting
   .."events" happen */

int
usbctl_next_state_on_event( int event )
{
    int next_state = device_state_machine[ sm_state ][ event ];

    LOG("\n");

    if ( next_state != kError )
    {
        int next_device_state = sm_state_to_device_state[ next_state ];
        printk( "%s%s --> [%s] --> %s. Device in %s state.\n",
                pszMe, state_names[ sm_state ], event_names[ event ],
                state_names[ next_state ], device_state_names[ next_device_state ] );

        sm_state = next_state;
        if ( usbd_info.state != next_device_state )
        {
            if ( configured_callback != NULL
                 &&
                 next_device_state == USB_STATE_CONFIGURED
                 &&
                 usbd_info.state != USB_STATE_SUSPENDED
               ) {
              configured_callback();
            }
            usbd_info.state = next_device_state;
        }
    }
#if 0
    else
        printk( "%s%s --> [%s] --> ??? is an error.\n",
                pszMe, state_names[ sm_state ], event_names[ event ] );
#endif
    return next_state;
}

//////////////////////////////////////////////////////////////////////////////
// Private Helpers
//////////////////////////////////////////////////////////////////////////////

void usb_driver_reset(void)
{
    printk("In usb_driver_reset, usb_speed= %d\n", usb_speed);
    desc_t * pdesc = s3c2410_usb_get_descriptor_ptr();
    config_desc_t *cfg;
    intf_desc_t *intf;
    intf_desc_t *intf_b;
    ep_desc_t *ep;
    acm_function * acm;
    /* setup device descriptor */
    pdesc->dev.idVendor = usb_vendor_id;
    pdesc->dev.idProduct    = usb_product_id;
    pdesc->dev.bNumConfigurations = 1;

    cfg = (config_desc_t*) (pdesc->cdb);

    cfg->bLength             = sizeof( config_desc_t );
    cfg->bDescriptorType     = USB_DESC_CONFIG;
    cfg->wTotalLength        = make_word_c( sizeof(config_desc_t) +
                           sizeof(intf_desc_t) * 2 +
                           sizeof(acm_function) +
                           sizeof(ep_desc_t) * 2);
    cfg->bNumInterfaces      = 2;
    cfg->bConfigurationValue = GS_ACM_CONFIG_ID;
    cfg->iConfiguration      = 0;
    cfg->bmAttributes        = 0xc0;//?
    cfg->MaxPower            = 0x01;

    intf = (intf_desc_t *) ( cfg + 1);
    intf->bLength            = sizeof( intf_desc_t );
    intf->bDescriptorType    = USB_DESC_INTERFACE;
    intf->bInterfaceNumber   = GS_CONTROL_INTERFACE_ID;
    intf->bAlternateSetting  = 0;
    intf->bNumEndpoints      = 1;
    intf->bInterfaceClass    = USB_CLASS_COMM;
    intf->bInterfaceSubClass = USB_CDC_SUBCLASS_ACM;
    intf->bInterfaceProtocol = USB_CDC_CTRL_PROTO_AT;
    intf->iInterface         = 0;

    acm = (acm_function *)(intf+1);
    acm->gs_call_mgmt_descriptor.bLength = 5;
    acm->gs_call_mgmt_descriptor.bDescriptorType = USB_DT_CS_INTERFACE;
    acm->gs_call_mgmt_descriptor.bDescriptorSubType = USB_CDC_CALL_MGMT;
    acm->gs_call_mgmt_descriptor.bmCapabilities = 0;
    acm->gs_call_mgmt_descriptor.bDataInterface = 0;

    acm->gs_acm_descriptor.bLength = 4;
    acm->gs_acm_descriptor.bDescriptorType = USB_DT_CS_INTERFACE;
    acm->gs_acm_descriptor.bDescriptorSubType = USB_CDC_ACM;
    acm->gs_acm_descriptor.bmCapabilities = 0x00;

    acm->gs_union_desc.bLength = 5;
    acm->gs_union_desc.bDescriptorType = USB_DT_CS_INTERFACE;
    acm->gs_union_desc.bDescriptorSubType = USB_CDC_UNION;
    acm->gs_union_desc.bMasterInterface0 = 0;
    acm->gs_union_desc.bSlaveInterface0 = 1;

    acm->gs_fullspeed_notify_desc.bLength = sizeof( ep_desc_t );
    acm->gs_fullspeed_notify_desc.bDescriptorType = USB_DESC_ENDPOINT;
    acm->gs_fullspeed_notify_desc.bEndpointAddress = 0x83;
    acm->gs_fullspeed_notify_desc.bmAttributes = USB_EP_INT;
    acm->gs_fullspeed_notify_desc.wMaxPacketSize = sizeof(SER_NOTIFY);
    acm->gs_fullspeed_notify_desc.bInterval = 0x01;

    intf_b = (intf_desc_t *) ( acm + 1);
    intf_b->bLength            = sizeof( intf_desc_t );
    intf_b->bDescriptorType    = USB_DESC_INTERFACE;
    intf_b->bInterfaceNumber   = GS_DATA_INTERFACE_ID;
    intf_b->bAlternateSetting  = 0;
    intf_b->bNumEndpoints      = 2;
    intf_b->bInterfaceClass    = USB_CLASS_CDC_DATA;
    intf_b->bInterfaceSubClass = 0;
    intf_b->bInterfaceProtocol = 0;
    intf_b->iInterface         = 0;

    ep = (ep_desc_t *) (intf_b + 1);
    ep[0].bLength             = sizeof( ep_desc_t );
    ep[0].bDescriptorType     = USB_DESC_ENDPOINT;
    ep[0].bEndpointAddress    = USB_EP_ADDRESS( 1, USB_IN );
    ep[0].bmAttributes        = USB_EP_BULK;
    if( usb_speed == USB_SPEED_HIGH )
        ep[0].wMaxPacketSize      = make_word( 512 );
    else
        ep[0].wMaxPacketSize      = make_word( 64 );
    ep[0].bInterval           = 0x01;

    ep[1].bLength             = sizeof( ep_desc_t );
    ep[1].bDescriptorType     = USB_DESC_ENDPOINT;
    ep[1].bEndpointAddress    = USB_EP_ADDRESS( 2, USB_OUT );
    ep[1].bmAttributes        = USB_EP_BULK;
    if( usb_speed == USB_SPEED_HIGH )
        ep[1].wMaxPacketSize      = make_word( 512 );
    else
        ep[1].wMaxPacketSize      = make_word( 64 );
    ep[1].bInterval  = 0x01;
    /* reset buffer */
//    rx_done = 0;
//    rx_size = 0;

//    printk("@after the init the descriptor & usb_connected = %d\n", usb_connected);

}

//* setup default descriptors */

static void initialize_descriptors(void)
{
    LOG("\n");

    desc.dev.bLength               = sizeof( device_desc_t );
    desc.dev.bDescriptorType       = USB_DESC_DEVICE;
    desc.dev.bcdUSB                = 0x0110; /* 1.0 */  // HS 0x200 ?????
    desc.dev.bDeviceClass          = USB_CLASS_COMM;    /* vendor specific */
    desc.dev.bDeviceSubClass       = 0;
    desc.dev.bDeviceProtocol       = 0;
    desc.dev.bMaxPacketSize0       = 8;    /* ep0 max fifo size, 16 orig ????? */
    desc.dev.idVendor              = 0; /* vendor ID undefined */
    desc.dev.idProduct             = 0;     /* product */
    desc.dev.bcdDevice             = 0;     /* vendor assigned device release num */
    desc.dev.iManufacturer         = 0; /* index of manufacturer string */
    desc.dev.iProduct              = 0;     /* index of product description string */
    desc.dev.iSerialNumber         = 0; /* index of string holding product s/n */
    desc.dev.bNumConfigurations    = 1; /* configurations we have */

    desc.qua.bLength               = sizeof( qua_desc_t );
    desc.qua.bDescriptorType       = USB_DESC_QUALIFIER;
    desc.qua.bcdUSB                = 0x0110;
    desc.qua.bDeviceClass          = USB_CLASS_COMM;    /* vendor specific */
    desc.qua.bDeviceSubClass       = 0;
    desc.qua.bDeviceProtocol       = 0;
    desc.qua.bMaxPacketSize0       = 8;    /* ep0 max fifo size, 16 or 64 ????? */
    desc.qua.bNumConfigurations    = 1;
    desc.qua.bRESERVED             = 0;


    // FIXME: Add support for all endpoint...
    usb_driver_reset();

    /* set language */
    /* See: http://www.usb.org/developers/data/USB_LANGIDs.pdf */
    sd_zero.bDescriptorType = USB_DESC_STRING;
    sd_zero.bLength         = sizeof( string_desc_t );
    sd_zero.bString[0]      = make_word_c( 0x409 ); /* American English */
    pxa_usb_set_string_descriptor( 0, &sd_zero );

}



//////////////////////////////////////////////////////////////////////////////
// Proc Filesystem Support
//////////////////////////////////////////////////////////////////////////////

#if CONFIG_PROC_FS
#define SAY( fmt, args... )  p += sprintf(p, fmt, ## args )
#define SAYV(  num )         p += sprintf(p, num_fmt, "Value", num )
#define SAYC( label, yn )    p += sprintf(p, yn_fmt, label, yn )
#define SAYS( label, v )     p += sprintf(p, cnt_fmt, label, v )

static int usbctl_read_proc(char *page, char **start, off_t off,
                int count, int *eof, void *data)
{
    const char * num_fmt   = "%25.25s: %8.8lX\n";
    const char * cnt_fmt   = "%25.25s: %lu\n";
    const char * yn_fmt    = "%25.25s: %s\n";
    const char * yes       = "YES";
    const char * no        = "NO";
    const char * mask      = "MASK";
    const char * enable    = "ENABLE";
    unsigned long v;
    unsigned long backup;
    char * p = page;
    int len;

    SAY( "S3C2410 USB Controller Core\n" );
    SAY( "USB state: %s (%s) %d\n",
        device_state_names[ sm_state_to_device_state[ sm_state ] ],
        state_names[ sm_state ],
        sm_state );

    SAYS( "ep0 bytes read", usbd_info.stats.ep0_bytes_read );
    SAYS( "ep0 bytes written", usbd_info.stats.ep0_bytes_written );
    SAYS( "ep0 FIFO read failures", usbd_info.stats.ep0_fifo_write_failures );
    SAYS( "ep0 FIFO write failures", usbd_info.stats.ep0_fifo_write_failures );

    v = UD_FIFO0;
    SAY( "%25.25s: 0x%8.8lX - %ld\n", "EP_FIFO0", v, v );


    SAY( "\n" );

    v = UD_FUNC;
    SAY( "%25.25s: 0x%8.8lX - %ld\n", "Address Register", v, v );

    backup = rINDEX_REG;

    rINDEX_REG = UD_INDEX_EP0;
    v = rMAXP_REG;
    SAY( "%25.25s: %ld (%8.8lX)\n", "EP0 size(EP0)", v, v );

    rINDEX_REG = UD_INDEX_EP2;
    v = rMAXP_REG;
    SAY( "%25.25s: %ld (%8.8lX)\n", "IN  max packet size(EP2)", v, v );
    rINDEX_REG = UD_INDEX_EP1;
    v = rMAXP_REG;
    SAY( "%25.25s: %ld (%8.8lX)\n", "OUT max packet size(EP1)", v, v );

    rINDEX_REG = backup;


    v = rPWR_REG;
    SAY( "\nUDC POWER Management Register\n" );
    SAYV( v );
    SAYC( "ISO Update(R)",    ( v & UD_PWR_ISOUP )     ? yes : no );
    SAYC( "USB Reset(R)",   ( v & UD_PWR_RESET ) ? yes : no );
    SAYC( "MCU Resume(RW)",  ( v & UD_PWR_RESUME  ) ? yes : no );
    SAYC( "Suspend Mode(R)",( v & UD_PWR_SUSPND ) ? yes : no );
    SAYC( "Suspend Mode enable bit(RW)",  ( v & UD_PWR_ENSUSPND ) ? yes : no );


    v = rEP_INT_REG;
    SAY( "\nUDC Interrupt Register\n" );
    SAYV( v );
    SAYC( "EP4 pending",        ( v & UD_INT_EP4 )     ? yes : no );
    SAYC( "EP3 pending",        ( v & UD_INT_EP3 )     ? yes : no );
    SAYC( "EP2 pending",        ( v & UD_INT_EP2 )     ? yes : no );
    SAYC( "EP1 pending",        ( v & UD_INT_EP1 )     ? yes : no );
    SAYC( "EP0 pending",        ( v & UD_INT_EP0 )     ? yes : no );

    v = rUSB_INT_REG;
    SAY( "\nUSB Interrupt Register\n" );
    SAYV( v );
    SAYC( "Reset",        ( v & UD_USBINT_RESET )     ? yes : no );
    SAYC( "Resume",        ( v & UD_USBINT_RESUM )     ? yes : no );
    SAYC( "Suspend",        ( v & UD_USBINT_SUSPND )     ? yes : no );

    v = rEP_INT_EN_REG;
    SAY( "\nUDC Interrupt Enable Register\n" );
    SAYV( v );
    SAYC( "EP4",                !( v & UD_INTE_EP4 )    ? mask : enable );
    SAYC( "EP3",                !( v & UD_INTE_EP3 )    ? mask : enable );
    SAYC( "EP2",                !( v & UD_INTE_EP2 )    ? mask : enable );
    SAYC( "EP1",                !( v & UD_INTE_EP1 )    ? mask : enable );
    SAYC( "EP0",                !( v & UD_INTE_EP0 )    ? mask : enable );

    v = rUSB_INT_EN_REG;
    SAY( "\nUSB Interrupt Enable Register\n" );
    SAYV( v );
    SAYC( "Reset",              !( v & UD_USBINTE_RESET )    ? mask : enable );
    SAYC( "Suspend",            !( v & UD_USBINTE_SUSPND )  ? mask : enable );

    len = ( p - page ) - off;
    if ( len < 0 )
         len = 0;
    *eof = ( len <=count ) ? 1 : 0;
    *start = page + off;
    return len;
}
#endif  /* CONFIG_PROC_FS */

#if defined(CONFIG_PM) && defined(CONFIG_MIZI)
void usbctl_suspend(void)
{
    /* TODO: FIXME: */
}

void usbctl_resume(void)
{
    /* TODO: FIXME: */
}
#endif


//////////////////////////////////////////////////////////////////////////////
// Module Initialization and Shutdown
//////////////////////////////////////////////////////////////////////////////
/*
 * usbctl_init()
 * Module load time. Allocate dma and interrupt resources. Setup /proc fs
 * entry. Leave UDC disabled.
 */
int usbctl_init( void )
{
    int retval = 0;

//#if CONFIG_MAX_ROOT_PORTS > 1
//    printk("check your kernel config.\n");
//    return -ENODEV;
//#endif
//
//    memset( &usbd_info, 0, sizeof( usbd_info ) );
//
//    usbd_info.dmach_tx = DMA_CH3; // ep1
//    usbd_info.dmach_rx = DMA_CH0; // ep2
//
//#if CONFIG_PROC_FS
//    create_proc_read_entry ( PROC_NODE_NAME, 0, NULL, usbctl_read_proc, NULL);
//#endif
//
//#ifdef USE_USBD_DMA
//    lsdkjflsdkjsdlkjflksdjf
//    /* setup dma */
//#if 1
//    retval = s3c2410_request_dma("USB", DMA_CH0,
//                                 ep1_dma_callback, NULL);
//    if (retval) {
//        printk("%sunable to register for dma rc=%d\n", pszMe, retval);
//        goto err_dma;
//    }
//
//    retval = s3c2410_request_dma("USB", DMA_CH2,
//                                 NULL, ep2_dma_callback);
//    if (retval) {
//        printk("%sunable to register for dma rc=%d\n", pszMe, retval);
//        goto err_dma;
//    }
//#else
//    retval = s3c2410_request_dma("USB", DMA_CH0,
//                                 ep1_dma_callback, ep2_dma_callback);
//    if (retval) {
//        printk("%sunable to register for dma rc=%d\n", pszMe, retval);
//        goto err_dma;
//    }
//#endif
//#endif // USE_USBD_DMA
//
//    /* now allocate the IRQ. */
//    retval = request_irq(IRQ_USBD, udc_int_hndlr, SA_INTERRUPT,
//              "S3C2410 USB core", NULL);
//    if (retval) {
//        printk("%sCouldn't request USB irq rc=%d\n",pszMe, retval);
//        goto err_irq;
//    }
//
//    /* MISC. register */
//    MISCCR &= ~MISCCR_USBPAD;
//    /* rUPLLCON */
//    rUPLLCON = FInsrt(0x78, fPLL_MDIV) | FInsrt(0x02, fPLL_PDIV)
//                | FInsrt(0x03, fPLL_SDIV);
//    /* rCLKCON */
//    rCLKCON |= CLKCON_USBD;
//        Clear_pending(INT_USBD);
//
//    printk( "S3C2410 USB Controller Core Initialized\n");
//    return 0;
//
//err_irq:
//
//#ifdef USE_USBD_DMA
//    s3c2410_free_dma(DMA_CH0);
//    s3c2410_free_dma(DMA_CH3);
//#endif
//
//err_dma:
//    usbd_info.dmach_tx = 0;
//    usbd_info.dmach_rx = 0;
    return retval;
}
/*
 * usbctl_exit()
 * Release DMA and interrupt resources
 */
void usbctl_exit( void )
{
    printk("Unloading S3C2410 USB Controller\n");

    rCLKCON &= ~CLKCON_USBD;

#ifdef CONFIG_PROC_FS
    remove_proc_entry ( PROC_NODE_NAME, NULL);
#endif

#ifdef USE_USBD_DMA
    s3c2410_free_dma(usbd_info.dmach_rx);
    s3c2410_free_dma(usbd_info.dmach_tx);
#endif
//    free_irq(IRQ_USBD, NULL);
}

void usb_soft_connect(int enable)
{
    //here use GPE13 to pull up D+, GPG12 to pull down D-, GPE12 to switch the pin from UART
    printk("first dump the pin config\n");

    //first switch pin to USB DEVICE
    rGPEDAT |= 1<<12;
    int i= 1000;
    while (i)
        i--;

    //then config D- out low
    printk("rGPGCON %x\n", rGPGCON);
    printk("rGPGDAT %x\n", rGPGDAT);
    printk("rGPGUP  %x\n", rGPGUP );

    rGPGCON &= ~(0xFF<<24);
    printk("rGPGCON %x\n", rGPGCON);
    rGPGCON |= 1<<24    ;
    printk("rGPGCON %x\n", rGPGCON);
    rGPGDAT &= ~(1<<12);

    printk("rGPGCON %x\n", rGPGCON);
    printk("rGPGDAT %x\n", rGPGDAT);
    printk("rGPGUP  %x\n", rGPGUP );

    printk("rGPECON %x\n", rGPECON);
    printk("rGPEDAT %x\n", rGPEDAT);
    printk("rGPEUP  %x\n", rGPEUP );

    rGPECON &= ~(3<<26);
    rGPECON |= 1<<26; //config as out pin
    if (!enable) {
        rGPEDAT |= 1<<13; //config as low, switch to ap usb port
    }
    else {
        rGPEDAT &= ~(1<<13); //config as high
    }

    printk("after config dump the pin config\n");
    printk("rGPECON %x\n", rGPECON);
    printk("rGPEDAT %x\n", rGPEDAT);
    printk("rGPEUP  %x\n", rGPEUP );

    printk("soft switch!!\n");
    printk("rGPECON %x\n", rGPECON);
    printk("rGPEDAT %x\n", rGPEDAT);
    printk("rGPEUP  %x\n", rGPEUP );

    printk("rGPECON %x\n", rGPECON);
    printk("rGPEDAT %x\n", rGPEDAT);
    printk("rGPEUP  %x\n", rGPEUP );

    dump_udcreg();
}

void usb_enumerate(void)
{

    usb_connected = 0;
    volatile u8 usb_ep_status, usb_dev_status;

    while (1) {
        u8 idx = rINDEX_REG;
        usb_ep_status = rEP_INT_REG;
        usb_dev_status = rUSB_INT_REG;

        if (usb_dev_status & UD_USBINT_RESET ) { //RESET interrupt
            DBGOUT(printk("!!!!!!!!!!!!!!!!!USB reset !!!!!!!!\n"));
            DBGOUT(printk("usb_ep_status %x, usb_dev_status %x\n", usb_ep_status, usb_dev_status));
            DBGOUT(printk("rPWR_REG            %x\n", rPWR_REG          ));

//            reconfig_usbd();
            rINDEX_REG = UD_INDEX_EP0;
            rMAXP_REG = UD_MAXP_8; // 8 byte

            /* clear interrupt */
            rUSB_INT_REG = UD_USBINT_RESET;


//            dump_udcreg();

//            rUSB_INT_REG = usb_dev_status;
//            break;
        }

        if (usb_dev_status & UD_USBINT_RESUM) { //RESUME
            DBGOUT(printk("!!!!!!!!!!!!!!!!!USB resume!!!!!!!!\n"));
            DBGOUT(printk("usb_ep_status %x, usb_dev_status %x\n", usb_ep_status, usb_dev_status));
            DBGOUT(printk("rPWR_REG            %x\n", rPWR_REG          ));

            /* clear interrupt */
            rUSB_INT_REG |= UD_USBINT_RESUM;
        }


        if (usb_dev_status & UD_USBINT_SUSPND) { //SUSPEND
            DBGOUT(printk("!!!!!!!!!!!!!!!!!USB suspend!!!!!!!!!!\n"));
            DBGOUT(printk("usb_ep_status %x, usb_dev_status %x\n", usb_ep_status, usb_dev_status));
            DBGOUT(printk("rPWR_REG            %x\n", rPWR_REG          ));

            /* clear interrupt */
            rUSB_INT_REG |= UD_USBINT_SUSPND;

        }

        if (usb_ep_status & UD_INT_EP0) { //ep0 interrrupt
            DBGOUT(printk("!!!!!!!!!!!!!!!!!USB ep0 irq!!!!!!!!\n"));
            DBGOUT(printk("usb_ep_status %x, usb_dev_status %x\n", usb_ep_status, usb_dev_status));
            DBGOUT(printk("rPWR_REG            %x\n", rPWR_REG          ));

            /* clear interrupt */
            rEP_INT_REG |= UD_INT_EP0;

//            printk("111after clear interrup!\n");
//            ShowVersion();
            ep0_int_hndlr();
//            dump_udcreg();
        }

        if ( usb_ep_status & UD_INT_EP1 ) {  //ep1 interrupt
            DBGOUT(printk("USB ep1 irq!!!!!!!!\n"));
            DBGOUT(printk("usb_ep_status %x, usb_dev_status %x\n", usb_ep_status, usb_dev_status));
            DBGOUT(printk("rPWR_REG            %x\n", rPWR_REG          ));

            /* clear interrupt */
            rEP_INT_REG |= UD_INT_EP1;

            ep1_int_hndlr(usb_ep_status);
        }

        if ( usb_ep_status & UD_INT_EP2 ) {   //ep2 interrupt
            DBGOUT(printk("USB ep2 irq!!!!!!!!\n"));
            DBGOUT(printk("usb_ep_status %x, usb_dev_status %x\n", usb_ep_status, usb_dev_status));
            DBGOUT(printk("rPWR_REG            %x\n", rPWR_REG          ));

            /* clear interrupt */
            rEP_INT_REG |= UD_INT_EP2;

            ep2_int_hndlr(usb_ep_status);

        }

        if ( usb_ep_status & UD_INT_EP3 ) {   //ep3 interrupt
            DBGOUT(printk("USB ep3 irq!!!!!!!!\n"));
            DBGOUT(printk("usb_ep_status %x, usb_dev_status %x\n", usb_ep_status, usb_dev_status));
            DBGOUT(printk("rPWR_REG            %x\n", rPWR_REG          ));

            /* clear interrupt */
            rEP_INT_REG = UD_INT_EP3;

        }

//        printk("interrupt done!!!!!!!\n");

        /* Restore old index */
           rINDEX_REG = idx;

           if (usb_connected) {
               break;
           }
    }
}


void usb_device_open(void)
{

    int count = 1000;
    volatile u8 usb_ep_status, usb_dev_status;

    while (count) {
        u8 idx = rINDEX_REG;
        usb_ep_status = rEP_INT_REG;
        usb_dev_status = rUSB_INT_REG;

        if (usb_dev_status & UD_USBINT_RESET ) { //RESET interrupt
            DBGOUT(printk("!!!!!!!!!!!!!!!!!USB reset !!!!!!!!\n"));
            DBGOUT(printk("usb_ep_status %x, usb_dev_status %x\n", usb_ep_status, usb_dev_status));
            DBGOUT(printk("rPWR_REG            %x\n", rPWR_REG          ));

//            reconfig_usbd();
            rINDEX_REG = UD_INDEX_EP0;
            rMAXP_REG = UD_MAXP_8; // 8 byte

            /* clear interrupt */
            rUSB_INT_REG = UD_USBINT_RESET;
           }

        if (usb_dev_status & UD_USBINT_RESUM) { //RESUME
            DBGOUT(printk("!!!!!!!!!!!!!!!!!USB resume!!!!!!!!\n"));
            DBGOUT(printk("usb_ep_status %x, usb_dev_status %x\n", usb_ep_status, usb_dev_status));
            DBGOUT(printk("rPWR_REG            %x\n", rPWR_REG          ));

            /* clear interrupt */
            rUSB_INT_REG |= UD_USBINT_RESUM;
        }


        if (usb_dev_status & UD_USBINT_SUSPND) { //SUSPEND
            DBGOUT(printk("!!!!!!!!!!!!!!!!!USB suspend!!!!!!!!!!\n"));
            DBGOUT(printk("usb_ep_status %x, usb_dev_status %x\n", usb_ep_status, usb_dev_status));
            DBGOUT(printk("rPWR_REG            %x\n", rPWR_REG          ));

            /* clear interrupt */
            rUSB_INT_REG |= UD_USBINT_SUSPND;

        }

        if (usb_ep_status & UD_INT_EP0) { //ep0 interrrupt
            DBGOUT(printk("!!!!!!!!!!!!!!!!!USB ep0 irq!!!!!!!!\n"));
            DBGOUT(printk("usb_ep_status %x, usb_dev_status %x\n", usb_ep_status, usb_dev_status));
            DBGOUT(printk("rPWR_REG            %x\n", rPWR_REG          ));

            /* clear interrupt */
            rEP_INT_REG |= UD_INT_EP0;

//            printk("111after clear interrup!\n");
//            ShowVersion();
            ep0_int_hndlr();
//            dump_udcreg();
        }

        if ( usb_ep_status & UD_INT_EP1 ) {  //ep1 interrupt
            DBGOUT(printk("USB ep1 irq!!!!!!!!\n"));
            DBGOUT(printk("usb_ep_status %x, usb_dev_status %x\n", usb_ep_status, usb_dev_status));
            DBGOUT(printk("rPWR_REG            %x\n", rPWR_REG          ));

            /* clear interrupt */
            rEP_INT_REG |= UD_INT_EP1;

            ep1_int_hndlr(usb_ep_status);
        }

        if ( usb_ep_status & UD_INT_EP2 ) {   //ep2 interrupt
            DBGOUT(printk("USB ep2 irq!!!!!!!!\n"));
            DBGOUT(printk("usb_ep_status %x, usb_dev_status %x\n", usb_ep_status, usb_dev_status));
            DBGOUT(printk("rPWR_REG            %x\n", rPWR_REG          ));

            /* clear interrupt */
            rEP_INT_REG |= UD_INT_EP2;

            ep2_int_hndlr(usb_ep_status);

        }

        if ( usb_ep_status & UD_INT_EP3 ) {   //ep3 interrupt
            DBGOUT(printk("USB ep3 irq!!!!!!!!\n"));
            DBGOUT(printk("usb_ep_status %x, usb_dev_status %x\n", usb_ep_status, usb_dev_status));
            DBGOUT(printk("rPWR_REG            %x\n", rPWR_REG          ));

            /* clear interrupt */
            rEP_INT_REG = UD_INT_EP3;

        }

//        printk("interrupt done!!!!!!!\n");

        /* Restore old index */
           rINDEX_REG = idx;

           count--;
    }
}


//EXPORT_SYMBOL( s3c2410_usb_open );
//EXPORT_SYMBOL( s3c2410_usb_start );
//EXPORT_SYMBOL( s3c2410_usb_stop );
//EXPORT_SYMBOL( s3c2410_usb_close );
//
//
//EXPORT_SYMBOL( s3c2410_usb_get_descriptor_ptr );
//EXPORT_SYMBOL( s3c2410_usb_set_string_descriptor );
//EXPORT_SYMBOL( s3c2410_usb_get_string_descriptor );
//EXPORT_SYMBOL( s3c2410_usb_kmalloc_string_descriptor );
//
//#if defined(CONFIG_PM) && defined(CONFIG_MIZI)
//EXPORT_SYMBOL( usbctl_resume );
//EXPORT_SYMBOL( usbctl_suspend );
//#endif

//module_init( usbctl_init );
//module_exit( usbctl_exit );

